package com.army.study.utils;

import com.army.study.ResourceTable;
import ohos.aafwk.ability.DataAbilityHelper;
import ohos.aafwk.ability.DataAbilityRemoteException;
import ohos.app.Context;
import ohos.data.distributed.common.KvManagerConfig;
import ohos.data.distributed.common.KvManagerFactory;
import ohos.data.resultset.ResultSet;
import ohos.media.photokit.metadata.AVStorage;
import ohos.utils.net.Uri;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 分布式文件管理
 */
public class DistributedFile extends Thread {
    private static final String TAG = DistributedFile.class.getSimpleName();

    // 0为图片文件类型
    public static final int FILE_TYPE_IMAGE = 0;
    // 1为音频文件类型
    public static final int FILE_TYPE_AUDIO = 1;
    // 2为视频文件类型
    public static final int FILE_TYPE_VIDEO = 2;
    // 3为文本文件类型
    public static final int FILE_TYPE_TEXT = 3;
    // 4为文件文件类型
    public static final int FILE_TYPE_FILE = 4;
    // 图片文件类型
    public static final int FILE_TYPE_UNKNOWN = 0xFF;

    // 缓存大小8M
    private static final int CACHE_SIZE = 8 * 1024;
    // 结束下标
    private static final int END_OF_FILE = -1;

    // 图片后辍
    private final String[] mImageType = {"jpg", "bmp", "jpeg", "png"};
    // 声频后辍
    private final String[] mAudioType = {"mp3", "wav", "flac"};
    // 视频后辍
    private final String[] mVideoType = {"mp4", "mjpeg"};
    // 文档后辍
    private final String[] mTextType = {"xml", "xlsx", "doc", "docx", "pdf", "txt"};

    // 上下文
    private final Context mContext;
    // 标识位，是否选择结果， 默认为false
    private boolean isCheckResult = false;

    // 存储本地文件信息
    private final ArrayList<String> localList = new ArrayList<>();
    // 存储分布式文件信息
    private final ArrayList<String> distributedList = new ArrayList<>();

    /**
     * 构造方法
     * @param context
     */
    public DistributedFile(Context context) {
        mContext = context;
    }

    /**
     * 多线程运行
     */
    @Override
    public void run() {
        // 初始化分布式文件
        initDistributedFiles();
        // 获取分布式文件
        getDistributedFiles();
        // 标识为已选择结果
        isCheckResult = true;
    }

    /**
     * 初始化分布式文件
     */
    private void initDistributedFiles() {
        // 图片外部存储URI
        searchFiles(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI);
        // 音频外部存储URI
        searchFiles(AVStorage.Audio.Media.EXTERNAL_DATA_ABILITY_URI);
        // 视频外部存储URI
        searchFiles(AVStorage.Video.Media.EXTERNAL_DATA_ABILITY_URI);

        searchFiles(AVStorage.Downloads.EXTERNAL_DATA_ABILITY_URI);

//        searchFiles(AVStorage.Files.fetchResource().EXTERNAL_DATA_ABILITY_URI);
    }

    private void searchFiles(Uri uri) {
        // 数据操作的辅助类
        DataAbilityHelper helper = DataAbilityHelper.creator(mContext);

        // 定义分布式显示字段
        String[] projections = new String[]{
                AVStorage.AVBaseColumns.ID,
                AVStorage.AVBaseColumns.DISPLAY_NAME,
                AVStorage.AVBaseColumns.DATA
        };

        try {
            // 根据uri查询出指定字段数据
            ResultSet resultSet = helper.query(uri, projections, null);
            if (resultSet == null) {
                LogUtil.info(TAG, "查询结果为空");
                return;
            }

            // 读取结果集数据出来
            while (resultSet.goToNextRow()) {
                // 媒体Id
                int mediaId = resultSet.getInt(resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.ID));
                // 文件路径
                String filePath = resultSet.getString(resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.DATA));
                // 从文件路径获取文件名
                String fileName = filePath.substring(filePath.lastIndexOf(File.separator) + 1);
                // 追加媒体Id到Uri
                Uri tmpUri = Uri.appendEncodedPathToUri(uri, mediaId+"");
                // 写文件到分布式目录下
                writeToDistributedDir(mContext, helper, fileName, tmpUri);
                // 添加文件名到本地存储列表
                localList.add(fileName);
            }

        } catch (DataAbilityRemoteException e) {
           LogUtil.error(TAG, "查询文件出错");
        }
    }

    /**
     * 写文件到分布式目录下
     * @param context
     * @param helper
     * @param fileName
     * @param tmpUri
     */
    private void writeToDistributedDir(Context context, DataAbilityHelper helper, String fileName, Uri tmpUri) {
        if (context.getDistributedDir() == null) {
            // 弹出1秒提示框，显示内容从资源文件获取，多语言文件
            WidgetHelper.showOneSecondTips(context, context.getString(ResourceTable.String_distributed_exception_info));
            return;
        }

        // 本地设备名称
        String deviceName = KvManagerFactory.getInstance().createKvManager(new KvManagerConfig(context))
                .getLocalDeviceInfo().getName();
        // 组合唯一名称，设备名称+文件名
        String uniqueFileName = deviceName + "+" + fileName;
        // 组合分布式文件路径
        String distributedFilePath = context.getDistributedDir().getPath() + File.separator + uniqueFileName;
        // 写入文件
        writeFile(distributedFilePath, helper, tmpUri);
    }

    /**
     * 写入文件
     * @param distributedFilePath
     * @param helper
     * @param tmpUri
     */
    private void writeFile(String distributedFilePath, DataAbilityHelper helper, Uri tmpUri) {
        // 输入流
        InputStream inputStream = null;
        // 输出流
        OutputStream outputStream = null;

        try {
            // 只读模式打开文件
            FileDescriptor fileDescriptor = helper.openFile(tmpUri, "r");
            // 根据文件路径生成空白文件
            File file = new File(distributedFilePath);
            // 把打开文件放到输入流
            inputStream = new FileInputStream(fileDescriptor);
            // 把生成空白文件放到输出流
            outputStream = new FileOutputStream(file);

            // 缓存区
            byte[] buffer = new byte[CACHE_SIZE];
            // 指针
            int count;
            // 循环读取输入流到缓存区, 值到读取到-1结束
            while ((count = inputStream.read(buffer)) != END_OF_FILE) {
                outputStream.write(buffer, 0, count);
            }
        } catch (DataAbilityRemoteException | IOException e) {
            LogUtil.error(TAG, "写到分布式目录出错: " + e);
        } finally {
            try {
                // 关闭输入流
                if (inputStream != null) {
                    inputStream.close();
                }
                // 关闭输出流
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                LogUtil.error(TAG, "关闭输入出流出错");
            }
        }
    }

    /**
     * 获取分布式文件
     */
    private void getDistributedFiles() {
        if (mContext.getDistributedDir() == null) {
            WidgetHelper.showOneSecondTips(mContext, mContext.getString(ResourceTable.String_distributed_exception_info));
            return;
        }

        // 初始化分布式路径文件对象
        File file = new File(mContext.getDistributedDir().getPath());
        // 获取文件对象下多个文件
        File[] files = file.listFiles();
        if (files == null) {
            LogUtil.error(TAG, "没有分布式文件");
            return;
        }

        // 循环获取文件添加到分布式列表
        for (File eachFile : files) {
            distributedList.add(eachFile.getPath());
        }
    }

    /**
     * 检查目标文件类型
     * @param fileName
     * @return
     */
    public int checkFileType(String fileName) {
        if (isDestFile(fileName, mImageType)) {
            return FILE_TYPE_IMAGE;
        }
        if (isDestFile(fileName, mAudioType)) {
            return FILE_TYPE_AUDIO;
        }
        if (isDestFile(fileName, mVideoType)) {
            return FILE_TYPE_VIDEO;
        }
        if (isDestFile(fileName, mTextType)) {
            return FILE_TYPE_TEXT;
        }

        return FILE_TYPE_UNKNOWN;
    }

    /**
     * 判断是否为配置类型文件
     * @param fileName
     * @param mImageType
     * @return
     */
    private boolean isDestFile(String fileName, String[] mImageType) {
        // 获取文件名是否包含.
        int idx = fileName.lastIndexOf(".");
        if (idx < 0) {
            return false;
        }
        // 获取文件名后辍
        String suffix = fileName.substring(idx + 1);

        for (String de : mImageType) {
            // 如果获取到文件名后辍在定义的数组里,返回true
            if (de.equals(suffix)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检查是否是本地设备
     * @param context
     * @param info 设备名称或设备Id
     * @param type 0为名称, 1为Id
     * @return
     */
    public static boolean isLocalDevice(Context context, String info, int type) {
        String result;
        // 获取设备名称
        if (type == 0) {
            result = KvManagerFactory.getInstance()
                    .createKvManager(new KvManagerConfig(context))
                    .getLocalDeviceInfo().getName();
        }else if (type == 1) {
            result = KvManagerFactory.getInstance()
                    .createKvManager(new KvManagerConfig(context))
                    .getLocalDeviceInfo().getId();
        }else {
            return false;
        }
        LogUtil.info(TAG, "info: " + info + ", result: " + result);
        return info.equals(result);
    }

    /**
     * 检查列表是否已被搜索过
     * @return
     */
    public boolean hasCheckResult() {
        return isCheckResult;
    }

    /**
     * 获取文件列表
     * @param type
     * @return
     */
    public List<String> getFile(int type) {
        // 根据类型获取文件列表
        if (distributedList.size() > 0) {
            return getFileList(distributedList, type);
        } else {
            return getFileList(localList, type);
        }
    }

    /**
     * 根据类型到列表匹配相应文件
     * @param distributedList
     * @param type
     * @return
     */
    private List<String> getFileList(List<String> distributedList, int type) {
        if (type == FILE_TYPE_FILE || distributedList.size() == 0) {
            return distributedList;
        }

        ArrayList<String> list = new ArrayList<>();
        for (String fileName : distributedList) {
            if (isTypeFile(fileName, type)) {
                list.add(fileName);
            }
        }
        return list;
    }

    /**
     * 根据类型获取文件
     * @param fileName
     * @param type
     * @return
     */
    private boolean isTypeFile(String fileName, int type) {
        if (type == FILE_TYPE_FILE) {
            return true;
        }
        if (type == FILE_TYPE_IMAGE) {
            return isDestFile(fileName, mImageType);
        }
        if (type == FILE_TYPE_AUDIO) {
            return isDestFile(fileName, mAudioType);
        }
        if (type == FILE_TYPE_VIDEO) {
            return isDestFile(fileName, mVideoType);
        }
        if (type == FILE_TYPE_TEXT) {
            return isDestFile(fileName, mTextType);
        }

        return false;
    }
}
